package com.xl.core.util.orc;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.Locale;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;

import com.github.jaiimageio.plugins.tiff.TIFFImageWriteParam;
import com.xl.core.constant.Globals;

/**
 * 对图片进行黑白锐化处理，可以提高识别成功率
 * 
 * @author Administrator
 * 
 */
public class ImageFilter {

	/**
	 * 省份证图片预处理，提高识别准确率
	 * 
	 * @param image
	 *            需要去噪的图像
	 * @throws IOException
	 */
	public static File cleanIdCardImage(File image) throws IOException {

		// 获取到文件的类型
		String fileName = image.getName();
		String imageFormat = fileName.substring(
				fileName.indexOf(Globals.DOT) + 1, fileName.length());

		// 图片文件转换为tif格式
		File imageFile = createTIFImage(image, imageFormat);

		// 临时目标文件夹
		File destF = new File(imageFile.getParentFile().getAbsolutePath(),
				"temp");
		if (!destF.exists()) {
			destF.mkdirs();
		}

		BufferedImage bufferedImage = ImageIO.read(imageFile);

		int h = bufferedImage.getHeight();
		int w = bufferedImage.getWidth();

		// 灰度化
		int[][] gray = new int[w][h];
		for (int x = 0; x < w; x++) {
			for (int y = 0; y < h; y++) {
				int argb = bufferedImage.getRGB(x, y);
				// 图像加亮（调整亮度识别率非常高）
				int r = (int) (((argb >> 16) & 0xFF) * 1.1 + 30);
				int g = (int) (((argb >> 8) & 0xFF) * 1.1 + 30);
				int b = (int) (((argb >> 0) & 0xFF) * 1.1 + 30);
				if (r >= 255) {
					r = 255;
				}
				if (g >= 255) {
					g = 255;
				}
				if (b >= 255) {
					b = 255;
				}
				gray[x][y] = (int) Math
						.pow((Math.pow(r, 2.2) * 0.2973 + Math.pow(g, 2.2)
								* 0.6274 + Math.pow(b, 2.2) * 0.0753), 1 / 2.2);
			}
		}

		// 二值化
		int threshold = ostu(gray, w, h);
		BufferedImage binaryBufferedImage = new BufferedImage(w, h,
				BufferedImage.TYPE_BYTE_BINARY);
		for (int x = 0; x < w; x++) {
			for (int y = 0; y < h; y++) {
				if (gray[x][y] > threshold) {
					gray[x][y] |= 0x00FFFF;
				} else {
					gray[x][y] &= 0xFF0000;
				}
				binaryBufferedImage.setRGB(x, y, gray[x][y]);
			}
		}

		// 输出临时文件
		File tempFile = new File(destF.getAbsolutePath(), fileName);
		ImageIO.write(binaryBufferedImage, imageFormat, tempFile);

		// 删除临时生成的TIF文件
		imageFile.delete();

		return tempFile;
	}

	/**
	 * 二值化
	 * 
	 * @param gray
	 * @param w
	 * @param h
	 * @return
	 */
	public static int ostu(int[][] gray, int w, int h) {
		int[] histData = new int[w * h];
		// Calculate histogram
		for (int x = 0; x < w; x++) {
			for (int y = 0; y < h; y++) {
				int red = 0xFF & gray[x][y];
				histData[red]++;
			}
		}

		// Total number of pixels
		int total = w * h;

		float sum = 0;
		for (int t = 0; t < 256; t++)
			sum += t * histData[t];

		float sumB = 0;
		int wB = 0;
		int wF = 0;

		float varMax = 0;
		int threshold = 0;

		for (int t = 0; t < 256; t++) {
			wB += histData[t]; // Weight Background
			if (wB == 0)
				continue;

			wF = total - wB; // Weight Foreground
			if (wF == 0)
				break;

			sumB += (float) (t * histData[t]);

			float mB = sumB / wB; // Mean Background
			float mF = (sum - sumB) / wF; // Mean Foreground

			// Calculate Between Class Variance
			float varBetween = (float) wB * (float) wF * (mB - mF) * (mB - mF);

			// Check if new maximum found
			if (varBetween > varMax) {
				varMax = varBetween;
				threshold = t;
			}
		}

		return threshold;
	}

	/**
	 * 图片文件转换为tif格式
	 * 
	 * @param imageFile
	 *            文件路径
	 * @param imageFormat
	 *            文件扩展名
	 * @return
	 * @throws IOException
	 */
	public static File createTIFImage(File imageFile, String imageFormat)
			throws IOException {
		Iterator<ImageReader> readers = ImageIO
				.getImageReadersByFormatName(imageFormat);
		ImageReader reader = readers.next();

		ImageInputStream iis = ImageIO.createImageInputStream(imageFile);
		reader.setInput(iis);
		// Read the stream metadata
		IIOMetadata streamMetadata = reader.getStreamMetadata();

		// Set up the writeParam
		TIFFImageWriteParam tiffWriteParam = new TIFFImageWriteParam(
				Locale.CHINESE);
		tiffWriteParam.setCompressionMode(ImageWriteParam.MODE_DISABLED);

		// Get tif writer and set output to file
		Iterator<ImageWriter> writers = ImageIO
				.getImageWritersByFormatName("tiff");
		ImageWriter writer = writers.next();

		BufferedImage bi = reader.read(0);
		IIOImage image = new IIOImage(bi, null, reader.getImageMetadata(0));

		String path = imageFile.getPath();
		StringBuffer strB = new StringBuffer(path);
		strB.insert(path.lastIndexOf('.'), 0);
		File tempFile = new File(strB.toString().replaceFirst(
				"(?<=//.)(//w+)$", "tif"));

		ImageOutputStream ios = ImageIO.createImageOutputStream(tempFile);
		writer.setOutput(ios);
		writer.write(streamMetadata, image, tiffWriteParam);
		ios.close();

		writer.dispose();
		reader.dispose();

		return tempFile;
	}

	/**
	 * 银行卡图片预处理，提高识别准确率
	 * 
	 * @param image
	 *            需要去噪的图像
	 * @throws IOException
	 */
	public static File cleanBankCardImage(File imageFile) throws IOException {

		// 获取到文件的类型
		String fileName = imageFile.getName();
		String imageFormat = fileName.substring(
				fileName.indexOf(Globals.DOT) + 1, fileName.length());

		// // 图片文件转换为tif格式
		// File imageFile = createTIFImage(image, imageFormat);

		// 临时目标文件夹
		File destF = new File(imageFile.getParentFile().getAbsolutePath(),
				"temp");
		if (!destF.exists()) {
			destF.mkdirs();
		}

		BufferedImage bufferedImage = ImageIO.read(imageFile);

		int h = bufferedImage.getHeight();
		int w = bufferedImage.getWidth();

		BufferedImage binaryBufferedImage = new BufferedImage(w, h,
				BufferedImage.TYPE_BYTE_BINARY);

		// 灰度化
		for (int x = 0; x < w; x++) {
			for (int y = 0; y < h; y++) {
				int argb = bufferedImage.getRGB(x, y);
				if (isBlackOrWhite(argb)) {
					binaryBufferedImage.setRGB(x, y, 0);
				} else {
					binaryBufferedImage.setRGB(x, y, 65535);
				}
			}
		}

		// 输出临时文件
		File tempFile = new File(destF.getAbsolutePath(), fileName);
		ImageIO.write(binaryBufferedImage, imageFormat, tempFile);

		// // 删除临时生成的TIF文件
		// imageFile.delete();

		return tempFile;
	}

	/**
	 * 获取到像素点是否属于黑白像素
	 * 
	 * @param colorInt
	 * @return
	 */
	public static boolean isBlackOrWhite(int colorInt) {
		if (getColorBright(colorInt) < 220 || getColorBright(colorInt) > 650) {
			return true;
		}
		return false;
	}

	/**
	 * 获取到像素点是否属于白像素
	 * 
	 * @param colorInt
	 * @return
	 */
	public static boolean isWhite(int colorInt) {
		if (getColorBright(colorInt) > 210) {
			return true;
		}
		return false;
	}

	public static int getColorBright(int colorInt) {
		Color color = new Color(colorInt);
		return color.getRed() + color.getGreen() + color.getBlue();
	}

	public static void main(String[] args) {

		File testDataDir = new File("E:\\图片\\temp\\205.jpg");
		try {
			// cleanBankCardImage(testDataDir);
			BufferedImage bufferedImage = ImageIO.read(testDataDir);

			int imageHeight = bufferedImage.getHeight();
			int imageWidth = bufferedImage.getWidth();
			BufferedImage newPic = new BufferedImage(imageWidth, imageHeight,
					BufferedImage.TYPE_3BYTE_BGR);
			float[] elements = { 0.0f, -1.0f, 0.0f, -1.0f, 4.0f, -1.0f, 0.0f,
					-1.0f, 0.0f, };
			Kernel kernel = new Kernel(3, 3, elements);
			ConvolveOp cop = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
			cop.filter(bufferedImage, newPic);

			BufferedImage binaryBufferedImage = new BufferedImage(imageWidth,
					imageHeight, BufferedImage.TYPE_BYTE_BINARY);

			// 灰度化
			for (int x = 0; x < imageWidth; x++) {
				for (int y = 0; y < imageHeight; y++) {
					int argb = bufferedImage.getRGB(x, y);
					if (isWhite(argb)) {
						binaryBufferedImage.setRGB(x, y, 0);
					} else {
						binaryBufferedImage.setRGB(x, y, 65535);
					}
				}
			}

			// 输出临时文件
			File tempFile = new File("E:\\图片\\temp\\temp_5.jpg");
			ImageIO.write(newPic, "jpg", tempFile);
		} catch (IOException e) {
			e.printStackTrace();
		}

	}
}